I posted a similar answer also to the question regarding imports from sibling packages. You can see it here.
Solution without sys.path
hacks
Summary
- Wrap the code into one folder (e.g.
packaged_stuff
)
- Create a
pyproject.toml
(older alternative: setup.py
)
- Pip install the package in editable state with
pip install -e <myproject_folder>
- Import using
from packaged_stuff.modulename import function_name
Setup
I assume the same folder structure as in the question
.
└── ptdraft
├── __init__.py
├── nib.py
└── simulations
├── __init__.py
└── life
├── __init__.py
└── life.py
I call the .
the root folder, and in my case it is located in C:\tmp\test_imports
.
Steps
1) Add a pyproject.toml
to the root folder
The contents of the pyproject.toml
can be simply
[project]
name = "ptdraft"
version = "0.1.0"
description = "My small project"
[build-system]
build-backend = "flit_core.buildapi"
requires = ["flit_core >=3.2,<4"]
Basically "any" valid pyproject.toml
would work. This is just a minimal working example, which uses flit as build backend.
2) Use a virtual environment
If you are familiar with virtual environments, activate one, and skip to the next step. Usage of virtual environments are not absolutely required, but they will really help you out in the long run (when you have more than 1 project ongoing..). The most basic steps are (run in the root folder)
- Create virtual env
- Activate virtual env
. venv/bin/activate
(Linux) or ./venv/Scripts/activate
(Win)
- Deactivate virtual env
To learn more about this, just Google out "python virtualenv tutorial" or similar. You probably never need any other commands than creating, activating and deactivating.
Once you have made and activated a virtual environment, your console should give the name of the virtual environment in parenthesis
PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>
3) pip install your project in editable state
Install your top level package (here ptdraft
) using pip
. The trick is to use the -e
flag when doing the install. This way it is installed in an editable state, and all the edits made to the .py files will be automatically included in the installed package. Note that the -e
flag with pyproject.toml requires pip 21.3 or newer.
In the root directory, run
pip install -e .
(note the dot, it stands for "current directory")
You can also see that it is installed by using pip freeze
(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///home/user/projects/ptdraft
Installing build dependencies ... done
Checking if build backend supports build_editable ... done
Getting requirements to build editable ... done
Preparing editable metadata (pyproject.toml) ... done
....
Successfully built ptdraft
Installing collected packages: ptdraft
Successfully installed ptdraft-0.1.0
(venv) PS C:\tmp\test_imports> pip freeze
ptdraft==0.1.0
4) Import by prepending mainfolder
to every import
In this example, the mainfolder
would be ptdraft
. This has the advantage that you will not run into name collisions with other module names (from python standard library or 3rd party modules).
Example Usage
nib.py
def function_from_nib():
print('I am the return value from function_from_nib!')
life.py
from ptdraft.nib import function_from_nib
if __name__ == '__main__':
function_from_nib()
Running life.py
(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
__init__.py
. S.Lott: I don't know how to check... – Canvassys.path
orPYTHONPATH
answers and checking out np8's excellent answer. Yes, it's a long read. Yes, it looks like a lot of work. But it's the only answer that actually solves the problem correctly and cleanly. – Kizzeepython -m
). – Breannabreannesys.path
. Nothing difficult or hackish about it. Note that the standard way is to not directly import any outside code at all - rather to install that code as a dependency using thepip
tool. – Avocado